﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once
#include "Vector3d.h"
#include "Vector4d.h"
#include "Matrix3d.h"

namespace gcmp
{
    /// \brief  4x4矩阵的定义
    ///
    /// 
    class GCMP_MATH_INTERFACE_EXPORT Matrix4d
    {
    public:
        DEFINE_VISUAL_TYPE_DOUBLE()

    public:
        /// \brief  构造单位矩阵
        ///
        /// \return 单位矩阵
        static Matrix4d CreateIdentityMatrix4d();

        /// \brief  设置当前矩阵为单位矩阵
        ///
        /// \return true: 成功， false:失败
        bool MakeIdentity();

        /// \brief  设置自身矩阵为绕空间任意轴的旋转矩阵
        ///
        /// \param pos  基点
        /// \param dir  轴方向
        /// \param radian  旋转角度
        /// \return true: 成功， false:失败
        bool MakeRotate(const Vector3d& pos, const Vector3d& dir, double radian);

        /// \brief   设置自身矩阵为平移矩阵
        ///
        /// \param t  平移量
        /// \return true:成功， false:失败
        bool MakeTranslate(const Vector3d & t);

        /// \brief  设置自身矩阵为空间任意平面的镜像矩阵
        ///
        /// \param pos  基点
        /// \param normal 法向
        /// \return  true:成功， false:失败
        bool MakeMirror(const Vector3d& pos, const Vector3d& normal);

        /// \brief  把矩阵本身变为逆矩阵
        ///
        /// \return true：成功， false, 失败
        bool MakeInverse();

        /// \brief  自身矩阵不变，返回自身矩阵的逆矩阵
        ///
        /// \param inversedMat 逆矩阵
        /// \return  true: 成功， false: 失败
        bool GetInverse(Matrix4d& inversedMat) const;

        /// \brief  自身矩阵不变，获得其转置矩阵
        ///
        /// \return  转置矩阵
        Matrix4d GetTranspose() const;

        /// \brief  返回矩阵中的代表平移的分量
        ///
        /// \return  平移分量
        Vector3d GetTranslation() const;

        /// \brief  返回三维旋转矩阵
        ///
        /// \return  三维旋转矩阵
        Matrix3d GetRotation() const;

        /// \brief   判断矩阵是否为单位阵
        ///
        /// \return  true: 是单位阵， false: 不是单位阵
        bool IsIdentity() const;

        /// \brief  计算矩阵行列式的值
        ///
        /// \return  行列式的值
        double Determinant() const;

        /// \brief  矩阵变换,当前矩阵乘以输入矩阵
        ///
        /// \param matrix  变换矩阵
        /// \return  true: 成功， false: 失败
        bool Transform(const Matrix4d& matrix);

    public:
        /// \brief  默认构造函数，单位矩阵
        /// 
        Matrix4d();

        /// \brief  构造函数，根据16个数值构造矩阵
        ///
        /// \param a11  第一行第一值
        /// \param a12  第一行第二值
        /// \param a13  第一行第三值
        /// \param a14  第一行第四值
        /// \param a21  第二行第一值
        /// \param a22  第二行第二值
        /// \param a23  第二行第三值
        /// \param a24  第二行第四值
        /// \param a31  第三行第一值
        /// \param a32  第三行第二值
        /// \param a33  第三行第三值
        /// \param a34  第三行第四值
        /// \param a41  第四行第一值
        /// \param a42  第四行第二值
        /// \param a43  第四行第三值
        /// \param a44  第四行第四值
        /// 
        Matrix4d(double a11, double a12, double a13, double a14,
            double a21, double a22, double a23, double a24,
            double a31, double a32, double a33, double a34,
            double a41, double a42, double a43, double a44);

        /// \brief   构造函数，四个三维行向量构造矩阵
        ///
        /// \param r1  旋转向量1
        /// \param r2  旋转向量2
        /// \param r3  旋转向量3
        /// \param t  t平移向量
        /// 
        Matrix4d(const Vector3d & r1, const Vector3d & r2, const Vector3d & r3, const Vector3d & t);

        /// \brief   构造函数，4个4维行向量构造矩阵
        ///
        /// \param r1   4维行向量
        /// \param r2   4维行向量
        /// \param r3   4维行向量
        /// \param r4   4维行向量
        ///
        Matrix4d(const Vector4d & r1, const Vector4d & r2, const Vector4d & r3,
            const Vector4d & r4);

        /// \brief    构造函数，旋转向量、平移向量构造矩阵
        ///
        /// \param r  旋转矩阵
        /// \param t  平移向量
        /// 
        Matrix4d(const Matrix3d & r, const Vector3d & t);

        /// \brief   矩阵的拷贝构造函数
        ///
        /// \param matrix  传入的矩阵
        /// 
        Matrix4d(const Matrix4d & matrix);

        /// \brief    由二维变换矩阵构造三维变换矩阵
        ///
        /// \param m  3x3表示的二维图形变换矩阵
        ///
        Matrix4d(const Matrix3d & m);

        /// \brief 设置矩阵的值
        ///
        /// \param a11  第一行第一值
        /// \param a12  第一行第二值
        /// \param a13  第一行第三值
        /// \param a14  第一行第四值
        /// \param a21  第二行第一值
        /// \param a22  第二行第二值
        /// \param a23  第二行第三值
        /// \param a24  第二行第四值
        /// \param a31  第三行第一值
        /// \param a32  第三行第二值
        /// \param a33  第三行第三值
        /// \param a34  第三行第四值
        /// \param a41  第四行第一值
        /// \param a42  第四行第二值
        /// \param a43  第四行第三值
        /// \param a44  第四行第四值
        /// \return  true: 成功， false:失败
        bool Set(
            double a11, double a12, double a13, double a14,
            double a21, double a22, double a23, double a24,
            double a31, double a32, double a33, double a34,
            double a41, double a42, double a43, double a44);

        /// \brief 设置矩阵
        ///
        /// \param m  四维数组
        /// \return true: 成功， false:失败
        bool Set(double m[4][4]);

        /// \brief 返回二维数组中某行的指针
        ///
        /// \param i  给定行
        /// \return true: 某行的指针
        double * operator [](int i);

        /// \brief 返回二维数组中某行的指针
        ///
        /// \param i  给定行
        /// \return true: 某行的指针
        const double * operator [](int i) const;

        /// \brief 自身矩阵乘以传入矩阵，结果设置为自身
        ///
        /// \param m  传入矩阵
        /// \return 自身矩阵的引用
        Matrix4d & operator *=(const Matrix4d & m);

        /// \brief 矩阵赋值操作
        ///
        /// \param m  传入矩阵
        /// \return 自身矩阵
        Matrix4d & operator =(const Matrix4d & m);

        /// \brief 设置当前矩阵为零矩阵
        /// 
        void MakeZero();

        /// \brief   返回矩阵中的旋转部分对应的坐标轴分量
        ///
        /// \param xAxis  x轴
        /// \param yAxis  y轴
        /// \param zAxis  z轴
        /// \return true:成功， false:失败
        bool GetRotationAxes(Vector3d& xAxis, Vector3d& yAxis, Vector3d& zAxis) const;

        /// \brief  设置矩阵的旋转矩阵和平移向量
        ///
        /// \param r  旋转矩阵
        /// \param t  平移向量
        /// \return  true:成功， false:失败
        bool SetRotationAndTranslation(const gcmp::Matrix3d& r, const Vector3d& t);

        /// \brief  设置自身矩阵为转置矩阵
        ///
        void MakeTranspose();
 
        /// \brief   根据平移向量的三个分量设置自身矩阵为平移矩阵
        ///
        /// \param tx  平移X分量
        /// \param ty  平移Y分量
        /// \param tz  平移Z分量
        ///
        void MakeTranslate(double tx, double ty, double tz);

        /// \brief  返回矩阵中的代表缩放的分量
        ///
        /// \return  缩放分量
        Vector3d GetScale() const;

        /// \brief   设置自身矩阵等比缩放矩阵
        ///
        /// \param pos   基点
        /// \param scale  缩放比例
        ///
        void MakeScale(const Vector3d& pos, double scale);

        /// \brief   设置自身矩阵非等比缩放矩阵
        ///
        /// \param pos  基点
        /// \param scales  缩放比例
        /// 
        void MakeScale(const Vector3d& pos, const Vector3d& scales);

        /// \brief  判断矩阵是否为镜像矩阵
        ///
        /// \return  true: 是镜像矩阵阵， false: 不是镜像阵
        bool IsMirror() const;

        /// \brief  判断对于二维对象是否是镜像矩阵
        ///
        /// \return  true: 是镜像矩阵阵， false: 不是镜像阵
        bool IsXOYMirror() const;

        /// \brief   是否是正交且等比缩放矩阵
        ///
        /// \param dScale  缩放比例
        /// \param dTol  误差
        /// \return true: 是， false:否
        bool IsOrthoScale(double & dScale, double dTol = gcmp::Constants::DOUBLE_EPS) const;

        /// \brief 把坐标系对象按照规定格式字符串输出
        ///
        /// \return 字符串
        std::wstring GetStringForDebug() const;

        /// \brief   根据字符串生成矩阵
        ///
        /// \param wstr  传入的字符串
        /// \return   生成的矩阵
        static OwnerPtr<Matrix4d> LoadFromString(const std::wstring& wstr);

    private:
        /// \brief   计算给定行和列的三阶行列式的值
        ///
        /// \param r1   给定行
        /// \param r2   给定行
        /// \param r3   给定行
        /// \param c1   给定列
        /// \param c2   给定列
        /// \param c3   给定列
        /// \return  列式的值
        double Determinant(int r1, int r2, int r3, int c1, int c2, int c3) const;

    private:
        double m_data[4][4];
    };


    /// \brief 两个矩阵相加
    ///
    /// \param m1  传入矩阵1
    /// \param m2  传入矩阵2
    /// \return 结果矩阵
    GCMP_MATH_INTERFACE_EXPORT Matrix4d operator+(const Matrix4d & m1, const Matrix4d & m2);

    /// \brief 两个矩阵相减
    ///
    /// \param m1  传入矩阵1
    /// \param m2  传入矩阵2
    /// \return 结果矩阵
    GCMP_MATH_INTERFACE_EXPORT Matrix4d operator-(const Matrix4d & m1, const Matrix4d & m2);

    /// \brief 两个矩阵相乘
    ///
    /// \param m1  传入矩阵1
    /// \param m2  传入矩阵2
    /// \return 结果矩阵
    GCMP_MATH_INTERFACE_EXPORT Matrix4d operator *(const Matrix4d & m1, const Matrix4d & m2);

    /// \brief 矩阵乘以列向量，返回列向量
    ///
    /// \param m  传入矩阵
    /// \param v  传入向量
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator *(const Matrix4d & m, const Vector4d & v);

    /// \brief 行向量乘以矩阵，返回行向量
    ///
    /// \param v  传入向量
    /// \param m  传入矩阵
    /// \return 结果向量
    GCMP_MATH_INTERFACE_EXPORT Vector4d operator *(const Vector4d & v, const Matrix4d & m);

    /// \brief 判断两矩阵是否相等
    ///
    /// \param m1   矩阵1
    /// \param m2   矩阵2
    /// \return true: 相等，false: 不相等
    GCMP_MATH_INTERFACE_EXPORT bool operator ==(const Matrix4d & m1, const Matrix4d & m2);

    /// \brief 判断两矩阵是否不相等
    ///
    /// \param m1   矩阵1
    /// \param m2   矩阵2
    /// \return true: 不相等，false: 相等
    GCMP_MATH_INTERFACE_EXPORT bool operator !=(const Matrix4d & m1, const Matrix4d & m2);

    /// \brief 判断两矩阵是否不相等
    ///
    /// \param m1   矩阵1
    /// \param m2   矩阵2
    /// \return true: 不相等，false: 相等
    GCMP_MATH_INTERFACE_EXPORT bool operator < (const Matrix4d & m1, const Matrix4d & m2);

} // namespace


